package data

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

type DouYinData struct {
	data *Data
}

func NewDouYinData(d *Data) *DouYinData {
	return &DouYinData{
		data: d,
	}
}

func dySign(nonceStr string, timestamp string, ticket string) string {
	data := []byte(fmt.Sprintf("nonce_str=%s&ticket=%s&timestamp=%s", nonceStr, ticket, timestamp))
	hash := md5.Sum(data)
	signature := hex.EncodeToString(hash[:])

	return signature
}

func (d *DouYinData) requestDyOpenTicket() (map[string]interface{}, error) {
	accessTokenResp, err := d.requestDyClientToken()
	fmt.Println(accessTokenResp)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("获取DY#OpenTicket异常: %v", err))
	}

	req, err := http.NewRequest("GET", "https://open.douyin.com/open/getticket/", nil)
	if err != nil {
		fmt.Println("创建请求时出错:", err)
		return nil, err
	}

	// 添加自定义header
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("access-token", accessTokenResp["access_token"].(string))

	// 创建一个HTTP客户端并发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Println("发送请求时出错:", err)
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == 200 {
		var responseMap map[string]interface{}
		err = json.NewDecoder(resp.Body).Decode(&responseMap)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("获取DY#OpenTicket异常: %v", err))
		}

		data := responseMap["data"].(map[string]interface{})
		errorCode := data["error_code"].(float64)
		description := data["description"].(string)

		if errorCode == 0 {
			ticket := data["ticket"].(string)
			expiresIn := data["expires_in"].(float64)

			return map[string]interface{}{
				"ticket":  ticket,
				"expired": int(time.Now().Unix()) + int(expiresIn) - 60,
			}, nil
		} else {
			return nil, errors.New(fmt.Sprintf("获取DY#OpenTicket异常: %v-%v", errorCode, description))
		}
	} else {
		return nil, errors.New(fmt.Sprintf("获取DY#OpenTicket异常: status_code=%v", resp.StatusCode))
	}
}

func (d *DouYinData) requestDyClientToken() (map[string]interface{}, error) {
	requestData := map[string]string{
		"client_key":    d.data.Config.DouYin.ClientKey,
		"client_secret": d.data.Config.DouYin.ClientSecret,
		"grant_type":    "client_credential",
	}

	requestBody, err := json.Marshal(requestData)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("获取DY#ClientToken异常: %v", err))
	}

	resp, err := http.Post("https://open-sandbox.douyin.com/oauth/client_token/", "application/json", bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, errors.New(fmt.Sprintf("获取DY#ClientToken异常: %v", err))
	}
	defer resp.Body.Close()

	if resp.StatusCode == 200 {
		var responseMap map[string]interface{}
		err = json.NewDecoder(resp.Body).Decode(&responseMap)
		if err != nil {
			return nil, errors.New(fmt.Sprintf("获取DY#ClientToken异常: %v", err))
		}

		data := responseMap["data"].(map[string]interface{})
		errorCode := data["error_code"].(float64)
		description := data["description"].(string)

		if errorCode == 0 {
			accessToken := data["access_token"].(string)
			expiresIn := data["expires_in"].(float64)

			return map[string]interface{}{
				"access_token": accessToken,
				"expired":      int(time.Now().Unix()) + int(expiresIn) - 60,
			}, nil
		} else {
			return nil, errors.New(fmt.Sprintf("获取DY#ClientToken异常: %v-%v", errorCode, description))
		}
	} else {
		return nil, errors.New(fmt.Sprintf("获取DY#ClientToken异常: status_code=%v", resp.StatusCode))
	}
}

func (d *DouYinData) generateRandomString(length int) (string, error) {
	randomBytes := make([]byte, length)
	_, err := rand.Read(randomBytes)
	if err != nil {
		return "", err
	}

	randomString := base64.URLEncoding.EncodeToString(randomBytes)
	// 去除编码中可能包含的特殊字符
	randomString = randomString[:length]

	return randomString, nil
}

func (d *DouYinData) GetDyShareSchema(videoUrl string) (string, error) {
	dyTicketSettings, err := d.requestDyOpenTicket()
	if err != nil {
		return "", err
	}

	ticket := dyTicketSettings["ticket"].(string)
	nonceStr, err := d.generateRandomString(16)
	if err != nil {
		return "", err
	}
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	signature := dySign(nonceStr, timestamp, ticket)

	videoURLEncoded := url.QueryEscape(videoUrl)
	shareURL := fmt.Sprintf("snssdk1128://openplatform/share?share_type=h5&client_key=%s&nonce_str=%s&timestamp=%s&signature=%s&video_path=%s&share_to_publish=1",
		d.data.Config.DouYin.ClientKey, nonceStr, timestamp, signature, videoURLEncoded)

	return shareURL, nil
}
